import Card from "../components/Card"
import Cards from "../components/Cards"
import { Fragment } from "react"
import Guide from "../components/layouts/Guide"
import Link from "next/link"
import CodeExample from "../components/CodeExample"
import CodeExamples from "../components/CodeExamples"
import { latestRelease } from "../docs/metadata/all"
import styles from "./get-started.scss"

<Guide title="开始">

# 开始使用 Vert.x

在本文中，您将学会如何开始编写一个新的 Vert.x Web 项目。

在正式开始前，您需要准备：

* JDK 1.8 或更高版本
* 文本编辑器或 IDE
* Maven 3 或更高版本
* curl 或 [HTTPie](https://httpie.org/) ，或浏览器，用于执行 HTTP 请求

<Fragment>

## <span className="get-started-step">1</span> 起步

<style jsx>{styles}</style>
</Fragment>

打开 [start.vertx.io](https://start.vertx.io) 网页创建一个新项目。

<a href="https://start.vertx.io" className="get-started-screenshot">
  <img src={require("../assets/get-started/starter-screenshot.png")} />
  <style jsx>{styles}</style>
</a>

选择您所需的 Vert.x 版本，Language 选择 Java，Build 选择 Maven，
然后输入您的 GroupId 和 ArtifactId。然后在 "Dependencies" 文本框输入 **Vert.x Web** 并将其选择添加为依赖。选择完成后，点击 **Generate Project** 按钮。
将zip文件保存到您的电脑，最后解压到任意目录。

以上步骤生成的项目包括：

* Maven 构建配置文件 `pom.xml` ，已配置如何构建、运行 Vert.x 程序
* Verticle 示例，及对应的 JUnit5 单元测试
* 指定了代码样式的 EditorConfig 插件配置
* Git 的忽略文件配置（.gitignore）

您也可以从以下地址直接下载示例项目：
<a href={`https://start.vertx.io/starter.zip?vertxDependencies=vertx-web&vertxVersion=${latestRelease.version}&jdkVersion=11`}>Maven</a> 或 <a href={`https://start.vertx.io/starter.zip?vertxDependencies=vertx-web&buildTool=gradle&vertxVersion=${latestRelease.version}&jdkVersion=11`}>Gradle</a>。

<Fragment>

## <span className="get-started-step">2</span> 编码

<style jsx>{styles}</style>
</Fragment>

在任意编辑器打开项目，然后打开 `src/main/java/com/example/starter/MainVerticle.java` 文件。
源码中包含一个示例 `Verticle` （Vert.x 的最小部署单元），该 Veticle 启动一个HTTP服务。
您需要修改这个文件，以响应所有请求。
更改代码，如下所示：

<CodeExamples>
<CodeExample title="Java">

```java
public class MainVerticle extends AbstractVerticle {
  @Override
  public void start() throws Exception {
    // 创建一个路由
    Router router = Router.router(vertx);

    // 挂载 Handler，接收所有请求路径和请求方法的请求
    router.route().handler(context -> {
      // 获取请求的远程地址
      String address = context.request().connection().remoteAddress().toString();
      // 获取请求参数 "name" 的取值
      MultiMap queryParams = context.queryParams();
      String name = queryParams.contains("name") ? queryParams.get("name") : "unknown";
      // 写json响应
      context.json(
        new JsonObject()
          .put("name", name)
          .put("address", address)
          .put("message", "Hello " + name + " connected from " + address)
      );
    });

    // 创建 HTTP 服务
    vertx.createHttpServer()
      // 使用路由处理所有请求
      .requestHandler(router)
      // 开始监听端口
      .listen(8888)
      // 打印监听的端口
      .onSuccess(server ->
        System.out.println(
          "HTTP server started on port " + server.actualPort()
        )
      );
  }
}
```

</CodeExample>

<CodeExample title="Kotlin">

```kotlin
class MainVerticle : AbstractVerticle() {
  override fun start() {
    // 创建一个路由
    val router = Router.router(vertx)

    // 挂载 Handler，接收所有请求路径和请求方法的请求
    router.route().handler { context ->
      // 获取请求的远程地址
      val address = context.request().connection().remoteAddress().toString()
      // 获取请求参数 "name" 的取值
      val queryParams = context.queryParams()
      val name = queryParams.get("name") ?: "unknown"
      // 写json响应
      context.json(
          json {
            obj(
              "name" to name,
              "address" to address,
              "message" to "Hello $name connected from $address"
            )
          }
      )
    }

    // 创建 HTTP 服务
    vertx.createHttpServer()
        // 使用路由处理所有请求
        .requestHandler(router)
        // 开始监听端口
        .listen(8888)
        // 打印监听的端口
        .onSuccess { server ->
          println("HTTP server started on port " + server.actualPort())
        }
  }
}
```

</CodeExample>

<CodeExample title="Groovy">

```groovy
class MainVerticle extends AbstractVerticle {
  @Override
  void start() {
    // 创建一个路由
    def router = Router.router(vertx)

    // 挂载 Handler，接收所有请求路径和请求方法的请求
    router.route().handler { context ->
      // 获取请求的远程地址
      def address = context.request().connection().remoteAddress().toString()
      // 获取请求参数 "name" 的取值
      def queryParams = context.queryParams()
      String name = queryParams.get("name") ?: "unknown"
      // 写json响应
      context.json(
        new JsonObject()
          .put("name", name)
          .put("address", address)
          .put("message", "Hello " + name + " connected from " + address)
      )
    }

    // 创建 HTTP 服务
    vertx.createHttpServer()
      // 使用路由处理所有请求
      .requestHandler(router)
      // 开始监听端口
      .listen(8888)
      // 打印监听的端口
      .onSuccess { server ->
        println("HTTP server started on port " + server.actualPort())
      }
  }
}
```

</CodeExample>
</CodeExamples>

以上代码创建了一个 Vert.x Web 路由（用于将HTTP请求路由到指定的请求处理器）
并以 `8888` 端口启动HTTP服务器。它对所有请求都返回一个JSON对象，内容包括请求的地址、 `name` 参数取值，以及欢迎信息。

<Fragment>

## <span className="get-started-step">3</span> 运行

<style jsx>{styles}</style>
</Fragment>

运行代码需要打开终端，并进入项目的目录。
通过以下命令构建应用：

```better-shell
$ mvn package
```

然后，运行应用：

```better-shell
$ mvn exec:java
HTTP server started on port 8888
apr 03, 2020 11:49:21 AM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
INFO: Succeeded in deploying verticle
```

现在服务已经启动了，可以发送请求进行测试：

<CodeExamples>
<CodeExample title="HTTPie">

```better-shell
$ http http://localhost:8888
HTTP/1.1 200 OK
content-length: 115
content-type: application/json; charset=utf-8

{
    "address": "0:0:0:0:0:0:0:1:32806",
    "message": "Hello unknown connected from 0:0:0:0:0:0:0:1:32806",
    "name": "unknown"
}

$ http http://localhost:8888\?name\="Francesco"
HTTP/1.1 200 OK
content-length: 119
content-type: application/json; charset=utf-8

{
    "address": "0:0:0:0:0:0:0:1:32822",
    "message": "Hello Francesco connected from 0:0:0:0:0:0:0:1:32822",
    "name": "Francesco"
}
```

</CodeExample>

<CodeExample title="curl">

```better-shell
$ curl -v http://localhost:8888
*   Trying ::1:8888...
* Connected to localhost (::1) port 8888 (#0)
> GET / HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.69.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< content-length: 115
<
* Connection #0 to host localhost left intact
{"name":"unknown","address":"0:0:0:0:0:0:0:1:59610","message":"Hello unknown connected from 0:0:0:0:0:0:0:1:59610"}

$ curl -v http://localhost:8888\?name\="Francesco"
*   Trying ::1:8888...
* Connected to localhost (::1) port 8888 (#0)
> GET /?name=Francesco HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.69.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< content-length: 119
<
* Connection #0 to host localhost left intact
{"name":"Francesco","address":"0:0:0:0:0:0:0:1:59708","message":"Hello Francesco connected from 0:0:0:0:0:0:0:1:59708"}
```

</CodeExample>
</CodeExamples>

<Fragment>

## <span className="get-started-step">4</span> 进一步了解

<style jsx>{styles}</style>
</Fragment>

现在您已经体验了 Vert.x 入门的乐趣，以下的指南可以帮助您进一步了解 Vert.x ：

<Cards columns={3}>
  <Card href="/introduction-to-vertx-and-reactive/" title="简介">
    阅读关于使用 Eclipse Vert.x 进行响应式编程的简介
  </Card>
  <Card href="/docs/" title="文档">
    深入研究文档，了解所有 Vert.x 模块
  </Card>
  <Card href="https://how-to.vertx.io/" title="How-tos">
    Vert.x How-tos：获取特定主题的实用指南
  </Card>
</Cards>

</Guide>
